from ipaddress import IPv4Address

from flask import current_app, request
from flask_restx import abort, reqparse
from sqlalchemy import or_
from zunclient.v1.containers import Container
from app.common.zstack_manager import ZStackManager
import time
from app.common.openstack_manager import OpenstackManager
from app.models import rangeModel, User, VmType
from app.models.logModel import LogDetailModel, LogModel
from tools import db, cache, ops
from utils.utils import base_detail, get_task_status

from .base_view import AdminValidators

#openstack
class SystemMonitoringAPI(AdminValidators):
    """
    系统监控
    since: 22.2.25
    """

    @cache.cached(timeout=60)
    def get(self):
        openstack_manager = OpenstackManager(
            current_app.config["OPENSTACK"], project_id=self.user.project_id
        )
        # 系统配额
        max_rate = openstack_manager.get_vm_max_rate_info()
        # 虚拟机开启
        vm_statics = {"vms": 0, "active_vms": 0}
        servers = openstack_manager.get_all_servers()
        for server in servers:
            vm_statics["vms"] += 1
            if server.status == "ACTIVE":
                vm_statics["active_vms"] += 1

        # admin身份
        admin_openstack_manager = OpenstackManager(
            current_app.config["ADMIN_OPENSTACK"]
        )
        hypervisors = admin_openstack_manager.admin_get_hypervisors(to_dict_detail=True)

        data = {
            "max_rate": max_rate,
            "hypervisors": hypervisors,
            "vm_statics": vm_statics,
        }
        return {"data": data}
#zstack
class NewSystemMonitoringAPI(AdminValidators):
    """
    系统监控
        stack
    """
    @cache.cached(timeout=60)
    def get(self):
        zstack_manager = ZStackManager()

        startTime = int(time.time()) - 900
        endTime = int(time.time())
        # 虚机总数
        data = zstack_manager.get_host_monitor(type='vmInstanceCount', startTime=startTime, endTime=endTime)
        hypervisors = zstack_manager.get_host_monitor(type='host')
        # # 虚拟机开启
        vm_statics = {"vms": 0, "active_vms": 0, "stop_vms": 0}
        for server in data['results'][0]['inventories']:
            # 总数量
            vm_statics["vms"] += 1
            if server['state'] == "Running":
                vm_statics["active_vms"] += 1
            if server['state'] == "Stopped":
                vm_statics["stop_vms"] += 1

        max_rate = zstack_manager.get_vm_max_rate_info()

        hy = []
        for h in hypervisors['results'][0]['inventories']:
            hy.append({'host_ip': h['managementIp'],
                       'name': h['name'],
                       'status': h['status'],
                       'vcpus': h['totalCpuCapacity'],
                       'local_disk_size': '',
                       'local_disk_used': '',
                       'vcpus_used': h['totalCpuCapacity'] - h['availableCpuCapacity'],
                       'memory_size': round(h['totalMemoryCapacity'] / 1024 / 1024 / 1024),
                       'memory_used': round(
                           (h['totalMemoryCapacity'] - h['availableMemoryCapacity']) / 1024 / 1024 / 1024)
                       })

        data = {
            "max_rate": max_rate,
            "hypervisors": hy,
            "vm_statics": vm_statics,
        }
        return {"data": data}


class VirtualMachinesMonitoringAPI(AdminValidators):
    """
    虚拟机监控
    since: 22.2.28
    """

    def _get_openstack_manager(self):
        openstack_manager = OpenstackManager(
            current_app.config["OPENSTACK"], project_id=self.user.project_id
        )
        return openstack_manager

    def get(self):
        params = request.args
        page = params.get("page", 1)
        page_size = params.get("pageSize", 10)
        source = params.get("source", "1")  # 来源  0=学生 1=教师
        range_name = params.get("rangeName")
        vm_type = params.get("vmType")
        vm_name = params.get("vmName")
        user = params.get("user")

        try:
            page = int(page)
            page_size = int(page_size)
        except:  # noqa
            page = 1
            page_size = 10

        openstack_manager = self._get_openstack_manager()
        server_id_to_info = openstack_manager.get_server_id_to_info()

        range_filters = []
        if range_name:
            range_filters.append(rangeModel.Range.name.contains(range_name))

        range_uuid_to_name = dict(
            rangeModel.db.session.query(
                rangeModel.RangeLinkModule.range_uuid, rangeModel.Range.name
            )
            .join(
                rangeModel.Range,
                rangeModel.Range.id == rangeModel.RangeLinkModule.range_id,
            )
            .filter(*range_filters)
            .all()
        )

        vm_filters = []
        if source == "1":
            _model = rangeModel.RangeVm
            if vm_name:
                vm_filters.append(_model.vm_name.contains(vm_name))
        else:
            _model = rangeModel.ActiveRangeVm
            if vm_name:
                vm_filters.append(_model.name.contains(vm_name))

        if range_name:
            vm_filters.append(_model.range_uuid.in_(range_uuid_to_name))
        if vm_type:
            vm_filters.append(_model.type == vm_type)
        if user:
            user_ids = User.query.filter(
                or_(
                    User.username.contains(user),
                    User.account_name.contains(user),
                )
            ).with_entities(User.id).all()
            vm_filters.append(_model.user_id.in_([item[0] for item in user_ids]))

        pagination = (
            _model.query.filter(*vm_filters)
            .order_by(_model.id.desc())
            .paginate(page, page_size, error_out=False)
        )
        data = {"current_page": page, "data": []}
        for vm in pagination.items:
            info = {
                "id": vm.id,
                "op_vm_uuid": vm.op_vm_uuid,
                "status": "NONE",
                "create_at": vm.create_time.strftime("%Y-%m-%d %H:%M:%S"),
                "range_name": range_uuid_to_name.get(vm.range_uuid),
                "vm_name": vm.vm_name if hasattr(vm, "vm_name") else vm.name,
                "vm_type": vm.type,
                "range_uuid": vm.range_uuid,
                "vm_uuid": vm.vm_uuid if hasattr(vm, "vm_uuid") else vm.new_vm_uuid,
                "ip": None,
                "user_info": {
                    "id": vm.user_id,
                    "name": vm.user.account_name
                }
            }
            if vm.op_vm_uuid:
                try:
                    # if vm.type == VmType.vm:
                    info["status"] = server_id_to_info[vm.op_vm_uuid]["status"]
                    info["ip"] = server_id_to_info[vm.op_vm_uuid]["ip"]
                    # if vm.type == VmType.container:
                    #     container: Container = ops.zun_operate.get_container_details(vm.op_vm_uuid)
                    #     info["status"] = 'ACTIVE' if container.status == "Running" else None
                    #     info["ip"] = list(container.addresses.values())[0][0]['addr']
                except:  # noqa
                    pass
            data["data"].append(info)
        data = base_detail(data, pagination)
        return data

    def post(self):
        parser = reqparse.RequestParser(bundle_errors=False)
        parser.add_argument("range_vm_id", help="参数不全!", required=True)
        parser.add_argument("source", default="1", required=True)  # 1=教师 0=学生
        parser.add_argument("action", help="请指定动作!", default="powerOff")
        params = parser.parse_args()

        if params["source"] == "1":
            range_vm = rangeModel.RangeVm.query.filter_by(
                id=params["range_vm_id"]
            ).first()
        else:
            range_vm = rangeModel.ActiveRangeVm.query.filter_by(
                id=params["range_vm_id"]
            ).first()

        if not range_vm:
            abort(400, message="虚拟机对象未找到!")

        if params["action"] == "powerOff" and range_vm.op_vm_uuid:
            openstack_manager = self._get_openstack_manager()
            server = openstack_manager.get_server_or_error(range_vm.op_vm_uuid)
            openstack_manager.stop_server(server)
            if params["source"] == "0":
                range_vm.status = "SHUTOFF"
                db.session.commit()
                get_task_status(f"{range_vm.range_uuid}_{range_vm.new_vm_uuid}", "")

        return {"code": 200, "msg": "关机正常!"}


class LogsMonitoringAPI(AdminValidators):
    """
    日志
    since: 22.3.3
    """

    def get(self):
        params = request.args
        page = params.get("page", 1)
        page_size = params.get("pageSize", 10)
        level = params.get("level")
        try:
            page = int(page)
            page_size = int(page_size)
        except:  # noqa
            page = 1
            page_size = 10

        filters = []
        if level:
            filters.append(LogModel.level == level)

        pagination = (
            LogModel.query.filter(*filters)
            .order_by(LogModel.id.desc())
            .paginate(page, page_size, error_out=False)
        )
        data = {"current_page": page, "data": []}
        for log in pagination.items:
            detail_info = (
                db.session.query(LogDetailModel.message)
                .filter(LogDetailModel.log_id == log.id)
                .scalar()
            )
            info = {
                "ip": str(IPv4Address(log.ip)) if log.ip else "0.0.0.0",
                "id": log.id,
                "operator": log.operator_name,
                "url": log.url_path,
                "method": log.method,
                "level": log.level,
                "title": log.url_path,
                "content": detail_info,
                "create_at": log.create_time.strftime("%Y-%m-%d %H:%M:%S"),
            }
            data["data"].append(info)
        data = base_detail(data, pagination)
        return data
